﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Shweet.Repository.Exceptions;
using System.IO;
using Microsoft.SharePoint.Linq;

namespace Shweet.Repository
{
    public class Teams : ITeams 
    {
        public void Add(List<Team> teams)
        {
            AddUsingSharePointAPI(teams);

            //Included for demonstration purposes only
            //AddUsingLinq(teams);
        }

        public void Remove(List<Team> teams)
        {
            SPList shweetTeamsList = GetShweetTeamsList();
            List<int> teamsToDelete = new List<int>();

            foreach (SPListItem item in shweetTeamsList.Items)
            {
                Team currentTeam = new Team()
                    {
                        Name = item.Title,
                        Url = item["Url"].ToString().Split(',')[0]
                    };

                if (teams.Contains(currentTeam))
                {
                    teamsToDelete.Add(item.ID);
                }
            }

            foreach (int id in teamsToDelete)
            {
                shweetTeamsList.Items.DeleteItemById(id);
            }
        }

        private static void AddUsingSharePointAPI(List<Team> teams)
        {
            SPList shweetTeamsList = GetShweetTeamsList();
            foreach (var team in teams)
            {
                SPListItem teamItem = shweetTeamsList.AddItem();
                teamItem["Title"] = team.Name;
                teamItem["Url"] = new SPFieldUrlValue() { Url = team.Url, Description = team.Name };
                teamItem.Update();
            }
        }

        // Included for demonstration purposes only.
        // Changing the Add method to use Linq will break tests and is an example
        // of how tests can be brittle
        //
        //private static void AddUsingLinq(List<Team> teams)
        //{
        //    using (var dataContext = new ShweetsDataContext(SPContext.Current.Web.Url))
        //    {
        //        EntityList<ShweetTeamsItem> shweetTeams = dataContext.GetList<ShweetTeamsItem>("ShweetTeams");
        //        foreach (Team team in teams)
        //        {
        //            ShweetTeamsItem item = new ShweetTeamsItem()
        //            {
        //                Url = team.Url,
        //                Title = team.Name
        //            };
        //            shweetTeams.InsertOnSubmit(item);
        //        }

        //        dataContext.SubmitChanges();
        //    }
        //}

        public List<Team> GetAll()
        {
            List<Team> teams = new List<Team>();
            using (var dataContext = new ShweetsDataContext(SPContext.Current.Web.Url))
            {
                StringBuilder sb = new StringBuilder();
                TextWriter tw = new StringWriter(sb);
                dataContext.Log = tw;

                //  This two phase query is much more in the style of Linq
                var query = (from t in dataContext.ShweetTeams
                             select new Team() { Url = t.Url.Split(',')[0], Name = t.Title });

                teams = query.ToList<Team>();
            }

            return teams;
        }

        public List<Team> Discover()
        {
            return DiscoverShweetEnabledSitesInWebApplication();
        }

        private static SPList GetShweetTeamsList()
        {
            SPContext context = SPContext.Current;
            SPWeb web = context.Web;
            SPList list = web.Lists.TryGetList("ShweetTeams");
            if (list == null)
            {
                throw new DataStoreNotFoundException("Shweet Team list not found in current site.");
            }
            return list;
        }

        /// <summary>
        /// NOTE: This method is to demonstrate how we are able test SPSecurity and 
        /// WebApplication.Sites, which are very common in SharePoint Projects.
        /// It is known that this would not be acceptable as it bypasses the security model and
        /// could give visibility of sites that the user does not have access.
        /// </summary>
        /// <returns></returns>
        private List<Team> DiscoverShweetEnabledSitesInWebApplication()
        {
            List<Team> teams = new List<Team>();


            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                foreach (
                    SPSite currentSite in
                        SPContext.Current.Site.WebApplication.Sites)
                {
                    foreach (SPWeb web in currentSite.AllWebs)
                    {
                        SPList shweetsList = web.Lists.TryGetList("Shweets");
                        if (shweetsList != null)
                        {
                            Team discoveredTeam = new Team()
                            {
                                Name = web.Title,
                                Url = ParseUrl(web.Url)
                            };
                            teams.Add(discoveredTeam);
                        }
                        web.Dispose();
                    }
                    currentSite.Dispose();
                }
            });

            return teams;
        }

        /// <summary>
        /// Get the absolute Url as this resolves issues with trailing / added by SharePoint to Url fields
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private string ParseUrl(string url)
        {
            Uri uri = new Uri(url);
            return uri.AbsoluteUri;
        }
    }
}
